/**
 * 
 */
package kr.co.insoft.driver.rackspace.process;

import java.io.Closeable;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import kr.co.insoft.driver.exception.DriverException;
import kr.co.insoft.driver.exception.ExceptionCode;
import kr.co.insoft.driver.rackspace.model.RackSpaceCredentialModel;
import kr.co.insoft.driver.rackspace.model.RackSpaceImageModel;

import org.jclouds.ContextBuilder;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.Image;
import org.jclouds.domain.Location;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import com.google.common.collect.ImmutableSet;
import com.google.common.io.Closeables;
import com.google.inject.Module;

/**
 * 이미지 정보를 반환하는 Process
 * 
 * @author IN-SOFT Inc. GoodwillDD(sylee@in-soft.co.kr)
 * 
 */
public class ImageProcess implements Closeable {

	private static final Logger logger = LoggerFactory
			.getLogger(ImageProcess.class);

	private final RackSpaceCredentialModel credentialModel;
	private final ComputeService computeService;

	public ImageProcess(RackSpaceCredentialModel credentialModel)
			throws DriverException {
		this.credentialModel = credentialModel;

		try {
			Assert.notNull(this.credentialModel);
			Assert.notNull(this.credentialModel.getUsername());
			Assert.notNull(this.credentialModel.getAccessKey());
		} catch (IllegalArgumentException e) {
			if (logger.isDebugEnabled()) {
				logger.debug("credentialModel : {}", this.credentialModel);
			}
			throw new DriverException(ExceptionCode.ARGUMENT_ERROR, e);
		}

		try {
			Iterable<Module> modules = ImmutableSet
					.<Module> of(new SLF4JLoggingModule());

			ComputeServiceContext context = ContextBuilder
					.newBuilder(this.credentialModel.getProvider())
					.credentials(this.credentialModel.getUsername(),
							this.credentialModel.getAccessKey())
					.modules(modules).buildApi(ComputeServiceContext.class);
			computeService = context.getComputeService();
		} catch (Exception e) {
			throw new DriverException(ExceptionCode.DRIVER_ERROR, e);
		}
	}

	private RackSpaceImageModel convert(Image image) throws DriverException {
		return new RackSpaceImageModel(image);
	}

	private Set<RackSpaceImageModel> convertCollections(
			Collection<? extends Image> images) throws DriverException {
		Set<RackSpaceImageModel> result = new HashSet<RackSpaceImageModel>();
		for (Image image : images) {
			result.add(new RackSpaceImageModel(image));
		}
		return result;
	}

	/**
	 * All Images
	 * 
	 * @return
	 */
	public Set<? extends Image> getImages() throws DriverException {
		try {
			return computeService.listImages();
		} catch (Exception e) {
			throw new DriverException(ExceptionCode.DRIVER_ERROR, e);
		}
	}

	/**
	 * All Image Convert to RackSpaceImageModel
	 * 
	 * @return
	 */
	public Set<RackSpaceImageModel> getImagesConvertRackSpace()
			throws DriverException {
		return convertCollections(getImages());
	}

	/**
	 * filter by zone
	 * 
	 * @param zone
	 * @return
	 */
	public Set<? extends Image> getImages(String zone) throws DriverException {
		Set<Image> result = new HashSet<Image>();
		Set<? extends Image> images = getImages();
		Location location = null;
		for (Image image : images) {
			location = image.getLocation();
			if (location.getId().equals(zone)) {
				result.add(image);
			}
		}
		return result;
	}

	/**
	 * filter by zone
	 * 
	 * @param zone
	 * @return
	 */
	public Set<RackSpaceImageModel> getImagesConvertRackSpace(
			String zone) throws DriverException {
		return convertCollections(getImages(zone));
	}
	
	public Set<RackSpaceImageModel> getMyImagesConvertRackSpace() throws DriverException {
		Set<RackSpaceImageModel> myImages = new HashSet<RackSpaceImageModel>();
		Set<RackSpaceImageModel> images = null;
		for(Location location : computeService.listAssignableLocations()) {
			images = convertCollections(getImages(location.getId()));
			for(RackSpaceImageModel model : images) {
				if ( model.getUserMetadata().get("image_type").equals("snapshot")) {
					myImages.add(model);
				}
			}
		}
		return myImages;
	}
	
	/**
	 * 생성한 Snapshot 만 반환한다.
	 * 
	 * @param zone
	 * @return
	 * @throws DriverException
	 */
	public Set<RackSpaceImageModel> getMyImagesConvertRackSpace(String zone) throws DriverException {
		Set<RackSpaceImageModel> images = convertCollections(getImages(zone));
		Set<RackSpaceImageModel> myImages = new HashSet<RackSpaceImageModel>();
		for(RackSpaceImageModel model : images) {
			if ( model.getUserMetadata().get("image_type").equals("snapshot")) {
				myImages.add(model);
			}
		}
		return myImages;
	}

	/**
	 * target image
	 * 
	 * @param id
	 *            zone and id
	 * @return
	 */
	public Image getImage(String id) throws DriverException {
		try {
			return computeService.getImage(id);
		} catch (Exception e) {
			throw new DriverException(ExceptionCode.DRIVER_ERROR, e);
		}
	}

	/**
	 * target image convert to RackSpaceImageModel
	 * 
	 * @param id
	 * @return
	 */
	public RackSpaceImageModel getImageConvertRackSpace(String id)
			throws DriverException {
		return convert(getImage(id));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.io.Closeable#close()
	 */
	@Override
	public void close() throws IOException {
		Closeables.close(computeService.getContext(), true);
	}

}
